package com.glsc.ngateway.common.base.weblog;

import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.TInterfaceAccessHistoryTable;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.TInterfaceAccessHistoryTableRepository;
import com.glsc.ngateway.common.base.service.MailServiceCommon;
import com.glsc.ngateway.common.base.utils.SpringUtilCommon;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;


@Service
public class WebLogService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    TInterfaceAccessHistoryTableRepository repo;

    @Resource
    MailServiceCommon mailServiceCommon;

    private final static Set<String> UN_LOG_INTERFACE_NAME_SET = new HashSet<>(){{
        add("ldap-checkToken");
    }};

    public Object aroundAdvice(ProceedingJoinPoint point, String appName) throws Throwable {
        return aroundAdvice(point, appName, null);
    }

    public Object aroundAdvice(ProceedingJoinPoint point, String appName, String account) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        String[] paramNames = methodSignature.getParameterNames();
        Object[] values = point.getArgs();
        StringBuffer params = new StringBuffer();
        for (int i = 0; i < paramNames.length; i++) {
            if (values[i] != null && paramNames[i] != null) {
                params.append(paramNames[i] + ":" + (i < values.length ? values[i].toString() : "")).append(i == paramNames.length - 1 ? "" : ",");
            }
        }
        String interfaceName = methodSignature.getName();


        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();

        MDC.put(MDCUtil.userKey, "user");
        MDC.put(MDCUtil.ipKey, request.getRemoteAddr());

        String url = request.getServletPath();
        String method = request.getMethod();
        Object[] args = point.getArgs();


        logger.info("Request------------------\r\nurl:{}\r\nip:{}\r\nmethod:{}\r\nargs:{}", url, request.getRemoteAddr(), method, args);
        LocalDateTime startdt = LocalDateTime.now();
        Object result = null;
        try {
            result = point.proceed(args);
            return result;
        } catch (Exception exception){
            logger.error("yichang",exception);
            if (exception instanceof PlatformException){
                PlatformException pe = (PlatformException)exception;
                if(pe.isSendMail2Admin()){
                    mailServiceCommon.sendMailToAdmin("网关"+ SpringUtilCommon.getApplicationName() +"的应用异常", exception.getMessage() + "\r\n" + Arrays.toString(exception.getStackTrace()));
                }
            } else {
                Object value = getPropertyValue(exception, "sendMail2Admin");
                if (value!= null && value instanceof Boolean && !(Boolean) value) {
                    //不发送消息的报警
                } else {
                    mailServiceCommon.sendMailToAdmin("网关"+ SpringUtilCommon.getApplicationName() +"的应用异常", exception.getMessage() + "\r\n" + Arrays.toString(exception.getStackTrace()));
                }
            }
            throw exception;
        } finally {
            LocalDateTime enddt = LocalDateTime.now();
            Duration duration = java.time.Duration.between(startdt, enddt);
            if (isLogRespone(url)){
                logger.info("Response------------------\r\nurl:{}\r\ncost:{}ms\r\nresult:{}", url, duration.toMillis(), result);
            }
            String paramStr = params.toString();
            if (paramStr.length() > 20 * 1024 + 10) {
                paramStr = paramStr.substring(0, 20 * 1024);
            }

            if(!UN_LOG_INTERFACE_NAME_SET.contains(appName + "-" + interfaceName)) {
                repo.save(TInterfaceAccessHistoryTable.builder()
                        .params(paramStr)
                        .interfaceName(appName + "-" + interfaceName)
                        .ip(request.getRemoteAddr())
                        .url(url)
                        .account(account)
                        .costTime(duration.toMillis())
                        .build());
            }
            MDC.clear();
        }
//        return result;
    }

    private boolean isLogRespone(String url) {
        boolean notLogFlag = url.endsWith("/demand/getDepartmentList")
                || url.endsWith("/demand/getUserList")
                || url.endsWith("/ehr/getAllEmps")
                || url.endsWith("/user/getUsrUrls")
                || url.endsWith("/system/main/listAll");
        return !notLogFlag;
    }

    public static Object getPropertyValue(Object obj, String propertyName) {
        Class<?> clazz = obj.getClass();

        try {
            Field field = clazz.getDeclaredField(propertyName);
            if (field!= null) {
                field.setAccessible(true);
                return field.get(obj);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

        return null;
    }
}
